package cn.xinfei.xdecision.engine.runner.executor.strategy.branch;

import cn.xinfei.xdecision.common.model.component.strategyout.StrategyOutput;
import cn.xinfei.xdecision.common.model.enginex.po.EngineAction;
import cn.xinfei.xdecision.common.model.enginex.po.EngineNode;
import cn.xinfei.xdecision.common.service.enginex.impl.EngineActionServiceImpl;
import cn.xinfei.xdecision.common.utils.enums.enginex.NodeTypeEnum;
import cn.xinfei.xdecision.common.utils.enums.enginex.action.ActionPostTypeEnum;
import cn.xinfei.xdecision.common.utils.enums.enginex.action.ActionServerEnum;
import cn.xinfei.xdecision.common.utils.enums.enginex.action.OldModelActionEnum;
import cn.xinfei.xdecision.common.utils.util.HttpClient;
import cn.xinfei.xdecision.common.utils.util.JsonUtils;
import cn.xinfei.xdecision.common.vo.FieldInfoVo;
import cn.xinfei.xdecision.engine.runner.context.PipelineContextHolder;
import cn.xinfei.xdecision.engine.runner.context.XDecisionContext;
import cn.xinfei.xdecision.engine.runner.executor.NodeHandler;
import cn.xinfei.xdecision.engine.runner.executor.model.StateTransmitModel;
import cn.xinfei.xdecision.engine.runner.executor.strategy.EngineNodeRunner;
import cn.xinfei.xdecision.httpclient.RestTemplateConfig;
import cn.xinfei.xdecision.nacos.NacosSwitchProperties;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.annotation.JSONField;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.gson.Gson;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpEntity;
import org.apache.http.ParseException;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutorService;

import static cn.xinfei.xdecision.common.utils.exception.enums.ErrorCodeEnum.ENGINE_POST_ACTION_ERROR;

@Service
@Slf4j
public class Action extends EngineNodeRunner {

    @Value("${xdecision.rcs.action.domain}")
    private String domain;

    @Value("${xdecision.rcs.action.startModelRun}")
    private String startModelRunUrl;

    @Resource
    private EngineActionServiceImpl engineActionService;

    @Resource(name = "bizProcessorThreadPool")
    private ExecutorService bizProcessorThreadPool;

    @Override
    public String getServiceName() {
        return EngineNodeRunner.PRE + NodeTypeEnum.ACTION.getType();
    }

    @Override
    public boolean terminalCondition(NodeHandler nodeHandler, Map<String, Object> nodeOutput, Map<String, Object> nodeInput) {
        return false;
    }

    @Override
    public Map<String, FieldInfoVo> getInputFieldInfo(NodeHandler nodeHandler) {
        return Collections.emptyMap();
    }


    @Override
    public Map<String, StrategyOutput> getOutputFieldInfo(NodeHandler nodeHandler) {
        return Collections.emptyMap();
    }

    @Override
    public Map<String, StrategyOutput> getTerminalOutputFieldInfo(NodeHandler nodeHandler) {
        return new HashMap<>();
    }

    @Override
    public StateTransmitModel runNode(NodeHandler nodeHandler) {
        StateTransmitModel stateTransmitModel = XDecisionContext.getContext().getStateContext();
        stateTransmitModel.setNextNodeCode(nodeHandler.getEngineNode().getNextNodeCodes());
        EngineNode engineNode = nodeHandler.getEngineNode();
        try {
            //获取动作
            LambdaQueryWrapper<EngineAction> wrapper = new LambdaQueryWrapper<>();
            EngineAction engineAction = engineActionService.getOne(
                    wrapper.eq(EngineAction::getVersionId, engineNode.getVersionId())
                            .eq(EngineAction::getNodeCode, engineNode.getNodeCode()));
            if (Objects.isNull(engineAction)) {
                log.warn("action null,nodeHandler===>{}", engineNode);
                return stateTransmitModel;
            }
            if (Objects.equals(engineAction.getPostType(), ActionPostTypeEnum.SYNC.getCode())) {
                //同步
                postAction(engineAction);
            } else if (Objects.equals(engineAction.getPostType(), ActionPostTypeEnum.ASYNC_THREAD.getCode())) {
                //异步线程
                CompletableFuture.runAsync(() -> postAction(engineAction), bizProcessorThreadPool);
            }
        } catch (Exception e) {
            log.error("action error,engineNode===>{}", engineNode, e);
        }
        return stateTransmitModel;
    }

    private void postAction(EngineAction engineAction) {
        try {
            if (Objects.equals(engineAction.getActionServer(), ActionServerEnum.OLD_ACTION_SERVER.getCode())) {
                ConcurrentMap<String, Object> contextValue = PipelineContextHolder.getContextValue();
                Map<String, Object> jsonObject = new HashMap<String, Object>();
                jsonObject.put("decision_set_id", PipelineContextHolder.getDecisionId());
                jsonObject.put("bus_type", OldModelActionEnum.getByType(engineAction.getActionInterface()));
                jsonObject.put("request_data", contextValue);
                if (NacosSwitchProperties.getNacosSwitchProperties().isDebugLog()) {
                    log.info("context:{}", contextValue);
                    log.info("actionParam:{}", JsonUtils.toJsonString(jsonObject));
                }
                //调老模型服务接口
//                RestTemplateConfig.post(domain + startModelRunUrl, jsonObject.toJSONString(), ENGINE_POST_ACTION_ERROR);
                RestTemplateConfig.post(domain + startModelRunUrl, JsonUtils.toJsonString(jsonObject), ENGINE_POST_ACTION_ERROR);
            }
        }catch (Exception e){

        }
    }

    public static void main(String[] args) {
//        Map<String,Object> data = new HashMap<String,Object>();
//        data.put("a",new BigDecimal(1.12));
//        data.put("b",new BigDecimal(2.1332));
//        Map<String,Object> jsonObject = new HashMap<String,Object>();
//        jsonObject.put("decision_set_id", PipelineContextHolder.getDecisionId());
//        jsonObject.put("request_data", data);
//        System.out.println(JsonUtils.toJsonString(jsonObject));

        Map<String,Object> object = new HashMap<String,Object>();
        object.put("finite",true);
        object.put("high",3476215962376601600d);
        object.put("infinite",false);
        object.put("low",0);
        object.put("naN",false);
        object.put("negative",false);
        JSONObject data = new JSONObject();
        data.put("a",1.12f);
        data.put("b",2.1332f);
        data.put("b",new BigDecimal(2.444));
//        data.put("personalloan_sd_creditlevel_norh_api_v3_3_1", object);
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("decision_set_id", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
        jsonObject.put("request_data",data);
        jsonObject.put("bus_type", "PERSONAL_ACTIVATE");

        System.out.println(JsonUtils.toJsonString(jsonObject));

        // 获得Http客户端(可以理解为:你得先有一个浏览器;注意:实际上HttpClient与浏览器是不一样的)
        CloseableHttpClient httpClient = HttpClientBuilder.create().build();

        // 创建Post请求
        HttpPost httpPost = new HttpPost("http://qa1-rcs-provider.testxinfei.cn/modelTask/startModelRun");
        // 响应模型
        CloseableHttpResponse response = null;
        try {
            // 由客户端执行(发送)
            // 我这里利用阿里的fastjson，将Object转换为json字符串;
            // (需要导入com.alibaba.fastjson.JSON包)
//            String jsonString = JSON.toJSONString(jsonObject);
//            String jsonString = JSONObject.toJSONString(jsonObject);
//            String jsonString = JsonUtils.toJsonString(jsonObject);
            ObjectMapper mapper = new ObjectMapper();
            String jsonString = mapper.writeValueAsString(jsonObject);
            JSONObject obj = mapper.readValue(jsonString, JSONObject.class);

            StringEntity entity = new StringEntity(jsonString, "UTF-8");
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_JSON_UTF8);
            // post请求是将参数放在请求体里面传过去的;这里将entity放入post请求体中
            httpPost.setEntity(entity);
            httpPost.setHeader("Content-Type", "application/json;charset=utf8");

            response = httpClient.execute(httpPost);
            // 从响应模型中获取响应实体
            HttpEntity responseEntity = response.getEntity();

            System.out.println("响应状态为:" + response.getStatusLine());
            if (responseEntity != null) {
                System.out.println("响应内容长度为:" + responseEntity.getContentLength());
                System.out.println("响应内容为:" + EntityUtils.toString(responseEntity));
            }
        } catch (ClientProtocolException e) {
            e.printStackTrace();
        } catch (ParseException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                // 释放资源
                if (httpClient != null) {
                    httpClient.close();
                }
                if (response != null) {
                    response.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }
    @Setter
    @Getter
    @ToString
    @AllArgsConstructor
    public class ModelRunWithTaskRequest {
        @JsonProperty("request_data")
        @JSONField(name = "request_data")
        private JSONObject requestData;

        @JsonProperty("decision_set_id")
        @JSONField(name = "decision_set_id")
        private String decisionSetId;
    }

}
